// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package testing

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"time"
)

type InternalExample struct {
	Name      string
	F         func()
	Output    string
	Unordered bool
}

// RunExamples是一个内部函数，但由于它是跨包的，所以被导出；
// 它是“go test”命令实现的一部分。
func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
	_, ok = runExamples(matchString, examples)
	return ok
}

func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) {
	ok = true

	var eg InternalExample

	for _, eg = range examples {
		matched, err := matchString(*match, eg.Name)
		if err != nil {
			fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
			os.Exit(1)
		}
		if !matched {
			continue
		}
		ran = true
		if !runExample(eg) {
			ok = false
		}
	}

	return ran, ok
}

func sortLines(output string) string {
	lines := strings.Split(output, "\n")
	sort.Strings(lines)
	return strings.Join(lines, "\n")
}

// processRunResult计算运行示例测试结果的摘要和状态。
// stdout是从测试的stdout捕获的输出。
// recovered是在运行测试后调用recover的结果，以防它惊慌失措。
// 
// 如果标准输出与预期输出不匹配，或者如果恢复为非零，则会将故障原因打印到标准输出。
// 如果测试是聊天/冗长的，它将向stdout打印一条成功消息。
// 如果recovered为非nil，它将使用该值进行恐慌。
// 如果测试因nil而惊慌，或者调用了runtime.Goexit，那么它将被
// 设置为失败并因errNilPanicOrGoexit而惊慌
func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, finished bool, recovered interface{}) (passed bool) {
	passed = true
	dstr := fmtDuration(timeSpent)
	var fail string
	got := strings.TrimSpace(stdout)
	want := strings.TrimSpace(eg.Output)
	if eg.Unordered {
		if sortLines(got) != sortLines(want) && recovered == nil {
			fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", stdout, eg.Output)
		}
	} else {
		if got != want && recovered == nil {
			fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want)
		}
	}
	if fail != "" || !finished || recovered != nil {
		fmt.Printf("--- FAIL: %s (%s)\n%s", eg.Name, dstr, fail)
		passed = false
	} else if *chatty {
		fmt.Printf("--- PASS: %s (%s)\n", eg.Name, dstr)
	}

	if recovered != nil {
		// 通过惊慌传播先前恢复的结果。
		panic(recovered)
	}
	if !finished && recovered == nil {
		panic(errNilPanicOrGoexit)
	}

	return
}
